package com.ideal.frame.sys.service;

import cn.hutool.core.lang.Assert;
import com.ideal.frame.jpa.DSLPageRequest;
import com.ideal.frame.jpa.JpaRepositoryImpl;
import com.ideal.frame.sys.dto.UserDto;
import com.ideal.frame.sys.entity.*;
import com.ideal.frame.sys.form.search.UserSearchForm;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.dml.UpdateClause;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * @Author: jin
 * @CreateTime: 2019-10-31 16:51
 * @Description: 用户管理逻辑层
 */
@Service
@Transactional
@Slf4j
public class SysUserService implements UserDetailsService {
    @PersistenceContext
    protected EntityManager entityManager;

    private JpaRepositoryImpl<SysUser, Long> userRepo;
    private JpaRepositoryImpl<SysUserRole, Long> userRoleRepo;

    @PostConstruct
    public void init() {
        this.userRepo = new JpaRepositoryImpl<>(SysUser.class, entityManager);
        this.userRoleRepo = new JpaRepositoryImpl<>(SysUserRole.class, entityManager);
    }

    QSysUser qSysUser = QSysUser.sysUser;
    QSysUserRole qSysUserRole = QSysUserRole.sysUserRole;

    @Autowired
    private SysRoleService roleService;
    @Autowired
    private SysMenuService menuService;
    @Autowired
    @Lazy
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        SysUser sysUser = getByUsername(s);
        // 判断用户是否存在
        if (sysUser == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        List<SysRole> roleList = roleService.getRolesByUserId(sysUser.getId());
        UserDto userDto = new UserDto(sysUser);
        userDto.setRoles(roleList);
        userDto.setPermissions(menuService.getPermissionByUser(sysUser.getId()));
        userDto.setMenus(menuService.getMenuTreeByUser(sysUser.getId()));
        return userDto;
    }

    /**
     * 根据用户名获取用户
     *
     * @param username
     * @return
     */
    public SysUser getByUsername(String username) {
        BooleanBuilder where = new BooleanBuilder();
        where.and(qSysUser.username.eq(username));
        where.and(qSysUser.status.isTrue());
        where.and(qSysUser.delFlag.isFalse());
        return userRepo.findOne(where);
    }

    /**
     * 获取用户分页列表
     *
     * @param searchForm
     * @return
     */
    public Page<SysUser> getPage(UserSearchForm searchForm) {
        DSLPageRequest pageRequest = searchForm.asDslPageRequest();
        if (StringUtils.isNotEmpty(searchForm.getUsername())) {
            pageRequest.addWhere(qSysUser.username.like("%" + searchForm.getUsername() + "%"));
        }
        if (StringUtils.isNotEmpty(searchForm.getRealName())) {
            pageRequest.addWhere(qSysUser.realName.like("%" + searchForm.getRealName() + "%"));
        }
        if (StringUtils.isNotEmpty(searchForm.getMobile())) {
            pageRequest.addWhere(qSysUser.mobile.like("%" + searchForm.getMobile() + "%"));
        }
        if (StringUtils.isNotEmpty(searchForm.getEmail())) {
            pageRequest.addWhere(qSysUser.email.like("%" + searchForm.getEmail() + "%"));
        }
        pageRequest.addWhere(qSysUser.delFlag.isFalse());
        return userRepo.findAll(pageRequest);
    }

    /**
     * 根据id获取用户对象
     *
     * @param id
     * @return
     */
    public SysUser getById(Long id) {
        SysUser user = userRepo.getOne(id);
        // 获取角色
        List<SysUserRole> roles = userRoleRepo.findAll(qSysUserRole.sysUser.id.eq(id));
        List<Long> ids = new ArrayList<>();
        roles.forEach(t -> ids.add(t.getSysRole().getId()));
        user.setRoleIds(ids);
        return user;
    }

    /**
     * 根据名称查询用户信息
     *
     * @param name
     * @return
     */
    public SysUser getByUserName(String name) {
        Optional<SysUser> user = userRepo.findOne(qSysUser.username.eq(name));
        return user.isPresent() ? user.get() : null;
    }

    @Transactional
    public String save(SysUser sysUser) {
        // 检查数据库中是否已经存在该用户信息,并且是删除的
        SysUser existsUser = getByUserName(sysUser.getUsername());
        Assert.isFalse(existsUser != null && !existsUser.isDelFlag() && sysUser.getId() != existsUser.getId(), "当前用户已存在");
        // 如果已经存在该用户信息且是删除的，操作是新增
        if (existsUser != null && existsUser.isDelFlag() && sysUser.getId() == null) {
            sysUser.setId(existsUser.getId());
            sysUser.setCreateTime(new Date());
            sysUser.setDelFlag(false);
            // 判断更新时，数据库中是否有相同的用户名(只有已存在账号不是删除才可)
        } else if (existsUser != null && existsUser.isDelFlag() && sysUser.getId() != existsUser.getId()) {
            userRepo.deleteById(existsUser.getId());
        }
        // 判断当前是否有id信息，如果没有添加创建时间
        if (sysUser.getId() == null) sysUser.setCreateTime(new Date());
        sysUser.setModifyTime(new Date());
        // 判断当前密码是否不为空，如果不为空，则对密码进行加密处理
        if (StringUtils.isEmpty(sysUser.getPassword()))
            sysUser.setPassword(passwordEncoder.encode("123456"));
            // 判断是否是更新，并且密码为空的情况，如果密码为空，则将原来的密码添加进去
        else if (sysUser.getId() != null && StringUtils.isEmpty(sysUser.getPassword())) {
            SysUser user = getById(sysUser.getId());
            sysUser.setPassword(user.getPassword());
        }
        SysUser user = userRepo.save(sysUser);
        // 删除角色
        if (sysUser.getRoleIds() != null && sysUser.getRoleIds().size() > 0) {
            userRoleRepo.deleteInBatch(userRoleRepo.findAll(qSysUserRole.sysUser.id.eq(user.getId())));
            List<SysUserRole> roles = new ArrayList<>();
            sysUser.getRoleIds().forEach(t -> {
                SysUserRole role = new SysUserRole();
                SysRole sysRole = new SysRole();
                sysRole.setId(t);
                role.setSysRole(sysRole);
                role.setSysUser(user);
                roles.add(role);
            });
            userRoleRepo.saveAll(roles);
        }
        return "";
    }

    @Transactional
    public void userDel(List<Long> ids) {
        UpdateClause updateClause = userRepo.updateClause();
        updateClause.set(QSysUser.sysUser.delFlag, true);
        updateClause.where(QSysUser.sysUser.id.in(ids));
        updateClause.execute();
    }

    @Cacheable(value = "resource", key = "'user'.concat(#userId)", unless = "#result == null || #result.size() == 0")
    public List<String> getPermissionsByUserId(String userId) {
        return null;
    }
}
